package org.tungse.redis.test;

/**
 * @Author : Tungse
 * @Date: 2025/7/1 9:15
 * @Description:
 */

import redis.clients.jedis.Jedis;

import java.util.UUID;

public class Redis限流示例 {
    public static void main(String[] args) throws InterruptedException {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.auth("foobared");
        jedis.del("PayRequest");
        //模拟发5个请求
        int cnt = 105;
        for (int i = 0; i < cnt; i++) {
            Thread.sleep(250);
            LimitUtilCopyOf.canVisit(jedis, "PayRequest", 1, 2);
        }
    }
}

/**
 * 重新逻辑
 */
class LimitUtilCopyOf {
    //判断是否需要限流
    public static void canVisit(Jedis jedis, String requestType, int limitTime, int limitNum) {
        long currentTime = System.currentTimeMillis();
        //去掉时间范围外（超时）的请求
        jedis.zremrangeByScore(requestType, 0, currentTime - limitTime * 1000);
        //统计时间范围内总数
        Long count = jedis.zcard(requestType);
        count += 1;
        boolean flag = limitNum >= count;
        if (flag) {
            //成功请求的进入限流记录
            //把请求放入zset
            jedis.zadd(requestType, currentTime, Long.valueOf(currentTime).toString());
            System.out.println("Can visit");
        } else {
            System.out.println("Can not visit");
        }

        //设置所有请求的超时时间
        jedis.expire(requestType, limitTime + 1);
    }
}


class LimitUtil {
    //判断是否需要限流
    public static void canVisit(Jedis jedis, String requestType, int limitTime, int limitNum) {
        long currentTime = System.currentTimeMillis();
        //把请求放入zset
        jedis.zadd(requestType, currentTime, Long.valueOf(currentTime).toString());
        //去掉时间范围外（超时）的请求
        jedis.zremrangeByScore(requestType, 0, currentTime - limitTime * 1000);
        //统计时间范围内总数
        Long count = jedis.zcard(requestType);
        //设置所有请求的超时时间
        jedis.expire(requestType, limitTime + 1);
        boolean flag = limitNum >= count;
        if (flag) {
            System.out.println("Can visit");
        } else {
            System.out.println("Can not visit");
        }
    }
}

class LimitUtilLua {

    // Lua脚本（使用SHA1缓存提高性能）
    private static final String LIMIT_SCRIPT =
            "local key = KEYS[1]\n" +
                    "local currentTime = tonumber(ARGV[1])\n" +
                    "local member = ARGV[2]\n" +
                    "local windowStart = tonumber(ARGV[3])\n" +
                    "local expireSec = tonumber(ARGV[4])\n" +
                    "\n" +
                    "redis.call('zadd', key, currentTime, member)\n" +
                    "redis.call('zremrangebyscore', key, 0, windowStart)\n" +
                    "local count = redis.call('zcard', key)\n" +
                    "redis.call('expire', key, expireSec)\n" +
                    "return count";

    public static void canVisit(Jedis jedis, String requestType, int limitTime, int limitNum) {
        long currentTime = System.currentTimeMillis();
        // 生成唯一请求ID（避免时间戳冲突）
        String member = UUID.randomUUID().toString();
        // 计算窗口起始时间（毫秒）
        long windowStart = currentTime - limitTime * 1000L;
        // 设置Key过期时间（窗口时间+缓冲时间）
        int expireSec = limitTime + 1;

        // 执行Lua脚本（确保原子操作）
        Long count = (Long) jedis.eval(
                LIMIT_SCRIPT,
                1,  // KEYS数量
                requestType,
                String.valueOf(currentTime),
                member,
                String.valueOf(windowStart),
                String.valueOf(expireSec)
        );

        boolean flag = limitNum >= count;
        if (flag) {
            System.out.println("Can visit (Requests: " + count + "/" + limitNum + ")");
        } else {
            System.out.println("Can not visit (Requests: " + count + "/" + limitNum + ")");
        }
    }
}